package cn.wolfcode.business.service.impl;

import java.io.IOException;
import java.io.InputStream;
import java.rmi.RemoteException;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import cn.wolfcode.business.vo.BpmnInfoVO;
import cn.wolfcode.common.utils.file.FileUploadUtils;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import cn.wolfcode.business.mapper.BpmnInfoMapper;
import cn.wolfcode.business.domain.BpmnInfo;
import cn.wolfcode.business.service.IBpmnInfoService;
import org.springframework.transaction.annotation.Transactional;

/**
 * 流程定义明细Service业务层处理
 * 
 * @author 白金之星
 * @date 2023-11-01
 */
@Service
@Transactional
public class BpmnInfoServiceImpl implements IBpmnInfoService 
{
    @Autowired
    private BpmnInfoMapper bpmnInfoMapper;
    @Autowired
    private RepositoryService repositoryService;

    /**
     * 查询流程定义明细
     * 
     * @param id 流程定义明细主键
     * @return 流程定义明细
     */
    @Override
    public BpmnInfo selectBpmnInfoById(Long id)
    {
        return bpmnInfoMapper.selectBpmnInfoById(id);
    }

    /**
     * 查询流程定义明细列表
     * 
     * @param bpmnInfo 流程定义明细
     * @return 流程定义明细
     */
    @Override
    public List<BpmnInfo> selectBpmnInfoList(BpmnInfo bpmnInfo)
    {
        return bpmnInfoMapper.selectBpmnInfoList(bpmnInfo);
    }

    /**
     * 新增流程定义明细
     * 
     * @param bpmnInfo 流程定义明细
     * @return 结果
     */
    @Override
    public int insertBpmnInfo(BpmnInfo bpmnInfo)
    {
        return bpmnInfoMapper.insertBpmnInfo(bpmnInfo);
    }

    /**
     * 修改流程定义明细
     * 
     * @param bpmnInfo 流程定义明细
     * @return 结果
     */
    @Override
    public int updateBpmnInfo(BpmnInfo bpmnInfo)
    {
        return bpmnInfoMapper.updateBpmnInfo(bpmnInfo);
    }

    /**
     * 批量删除流程定义明细
     * 
     * @param ids 需要删除的流程定义明细主键
     * @return 结果
     */
    @Override
    public int deleteBpmnInfoByIds(Long[] ids)
    {
        return bpmnInfoMapper.deleteBpmnInfoByIds(ids);
    }

    /**
     * 删除流程定义明细信息
     * 
     * @param id 流程定义明细主键
     * @return 结果
     */
    @Override
    public void deleteBpmnInfoById(Long id)
    {
        //参数校验
        if(id == null ){
            throw new RuntimeException("非法参数");
        }

        BpmnInfo bpmnInfo = bpmnInfoMapper.selectBpmnInfoById(id);
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(bpmnInfo.getProcessDefinitionKey())
                .processDefinitionVersion(bpmnInfo.getVersion())
                .singleResult();
        //删除bpmn集成
        bpmnInfoMapper.deleteBpmnInfoById(id);
        //删除流程定义信息
        repositoryService.deleteDeployment(processDefinition.getDeploymentId(),true);
    }

    @Override
    public void deploy(BpmnInfoVO vo) throws IOException {
        if(vo == null) {
            throw new RuntimeException("参数异常");
        }
        //校验是否有文件
        if(vo.getFile() == null || vo.getFile().getSize() == 0){
            throw new RemoteException("请选择文件");
        }
        //校验文件是否是bpmn格式
        String extension = FileUploadUtils.getExtension(vo.getFile());
        if(!"bpmn".equalsIgnoreCase(extension)){
            throw new RuntimeException("文件格式必须为bpmn格式");
        }
        //把bpmn文件部署到active中
        Deployment deploy = repositoryService
                .createDeployment()
                .addInputStream(vo.getBpmnLabel(), vo.getFile().getInputStream())
                .deploy();
        //查询定义流程
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploy.getId())
                .singleResult();
        //把 bpmnInfo 信息保存到数据库中
        BpmnInfo busBpmnInfo = new BpmnInfo();
        busBpmnInfo.setBpmnLabel(vo.getBpmnLabel());
        busBpmnInfo.setBpmnType(vo.getBpmnType());
        busBpmnInfo.setDeployTime(new Date());
        busBpmnInfo.setInfo(vo.getInfo());
        busBpmnInfo.setProcessDefinitionKey(processDefinition.getKey());
        busBpmnInfo.setVersion(Integer.parseInt(processDefinition.getVersion()+""));
        bpmnInfoMapper.insertBpmnInfo(busBpmnInfo);
    }

    /**
     * 查看流程文件/流程图片
     * @param type
     * @param id
     * @return
     */
    @Override
    public InputStream getBpmn(String type, Long id) {
        if(id == null || !("xml".equalsIgnoreCase(type) || "png".equalsIgnoreCase(type))){
            throw new RuntimeException("参数异常");
        }
        BpmnInfo bpmnInfo = bpmnInfoMapper.selectBpmnInfoById(id);
        if(bpmnInfo == null) {
            throw new RuntimeException("参数异常");
        }
        //判断类型是 xml 还是 png,如果是 xml 响应 xml 如果是图片响应图片
        //查询流程定义信息
        InputStream inputStream = null;
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(bpmnInfo.getProcessDefinitionKey())
                .processDefinitionVersion(bpmnInfo.getVersion())
                .singleResult();
       if("xml".equalsIgnoreCase(type)){
        inputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(),processDefinition.getResourceName());
       }else if("png".equalsIgnoreCase(type)){
           DefaultProcessDiagramGenerator processDiagramGenerator = new DefaultProcessDiagramGenerator();
           BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
           /**
            * 第一个参数: 流程定义模型
            * 第二个参数: 高亮节点集合
            * 第三个参数: 高亮连线集合
            */
           inputStream = processDiagramGenerator.generateDiagram(bpmnModel,
                   Collections.emptyList(),
                   Collections.emptyList(),
                   "宋体",
                   "宋体",
                   "宋体");
        }else{
           throw new RuntimeException("非法操作");
       }

        return inputStream;
    }
}
